%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: 
%% Progress to usefulness: 
%%
%% Iterative approach to lookup, as described in 
%% the original Chord paper. 
%% 
%%%%%%%%%%%%%%%%%%%%%%%

-module(chord_iterative).
-include("db.hrl").

-export([lookup_call/3, find_successor/2, find_successor_call/3, find_predecessor/2, find_predecessor_call/3]).

-import(chord_lib, [dbg_str/2, dbg_format/3, dbg_header/2]).
-import(chord_lib, [dbg_msg/2, dbg_msg_loc/2]).
-import(chord_lib, [get_node/1, get_pid/1, get_position/1]).
-import(chord_lib, [get_finger/2, set_finger/3, finger_start/2, get_M/0, modspace/1]).


lookup_call(Key, From, State) ->
    dbg_format("Looking up key ~p on behalf of caller ~p~n", [Key, From], State),
    Hash = hash:hash(Key),
    N = find_successor(Hash, State),
    %% And reply to caller, by using gen_server:reply,
    %% the caller thinks he made a synchronous call
    gen_server:reply(From, N#node.node).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Functions for logic, 
%% depending on node interaction
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

find_successor_call(Id, From, State) ->
    Suc = find_successor(Id, State),
    gen_server:reply(From, Suc).

%% With the help of the other nodes, find the immediate 
%% successor node to the identifier Id. 
find_successor(Id, State) ->
  dbg_format("find_successor: Finding suc for pos ~B~n", [Id], State),
  Self = State#chord.identity,
  N2 = case Id == Self#node.position of
    true ->
      dbg_str("find_successor: Asking for the identity node~n", State),
      Self;
    false ->
      find_predecessor(Id, State)
  end,
  chord_lib:wrap_get_successor(State, N2).

find_predecessor_call(Id, From, State) ->
    Pred = find_predecessor(Id, State),
    gen_server:reply(From, Pred).

%% With the help of the other nodes, find the immediate 
%% predecessor node to the identifier Id. 
find_predecessor(Id, State) ->
  dbg_format("find_predecessor: Finding pred for pos ~B~n", [Id], State),
  N2 = State#chord.identity,
  case Id == N2#node.position of
    true ->
      dbg_str("find_predecessor: Asking for the identity node~n", State),
      chord_lib:wrap_get_predecessor(State, N2);
    false ->
      test_find_predecessor(N2, Id, State)
  end.

test_find_predecessor(N2, Id, State) ->
  Suc = chord_lib:wrap_get_successor(State, N2),
  N2p = N2#node.position,
  Sucp = Suc#node.position,
  % or n2p == sucp = if theres only one node

  %case ((N2p < Id) and (Id =< Sucp)) or (N2p == Sucp) of
  case intmath:interval_check_exc_inc(N2p, Id, Sucp) or (N2p == Sucp) of
    true  ->
      dbg_format("test_find_predecessor: Success with ~p at ~B~n",
                [N2#node.node, N2p], State),
      N2;
    false ->
      dbg_format("test_find_predecessor: Fail with ~p at ~B~n",
                [N2#node.node, N2p], State),
      N22 = chord_lib:wrap_closest_preceding_finger(State, N2, Id),
      N22p = N22#node.position,
      case N22p == N2p of
        true ->
          error("test_find_predecessor: test_find_predecessor not working~n"),
          N2;
        false ->
          test_find_predecessor(N22, Id, State)
        end
  end.

